/* $Id: script.js 594 2011-02-17 07:41:06Z noriko.harashima@gmail.com $ */

$(function()
{
////////////////////////////////////////////////////////////////////////////////
//
// グローバル
//
////////////////////////////////////////////////////////////////////////////////
/**
 * 変数
 */
var g_topic_id = 1; 
var g_scale = 1;
var g_color = "";
var g_idea_map = {};
var g_connected_user_list = [];
var g_selected_id = new Array();
var g_canvas_layer = $("#canvas_layer");
var g_scroll_layer = $("#scroll_layer");
var g_view_layer = $("#view_layer");

/**
 * 定数
 */
var MESSAGE_USER_ID = 0;
var MESSAGE_TOPIC_ID = 1;
var MESSAGE_IDEA_ID = 2;
var MESSAGE_TEXT = 3;
var MESSAGE_COLOR = 4;
var MESSAGE_PARENT_ID = 5;
var DEFAULT_NAME = "名無し";

/**
 * ビューレイヤーの初期位置とキャンバスレイヤーの初期値を足した座標
 * 
 */
var dragDelta = {
	top: g_view_layer.offset().top +
		 g_canvas_layer.offset().top,
	left: g_view_layer.offset().left +
		  g_canvas_layer.offset().left,
	};

/**
 * 現在のスケールを取得する。
 * @return スケール(0～1) 
 */
function getGlobalScale()
{
	return g_scale;
}

/**
 * クライアントカラーを取得する。
 * @return 色
 */
function getGlobalColor()
{
	if (g_color == "")
	{
		// クライアントの色を決める（ランダム）
		var color_rgb = [];
		color_rgb[0] = Math.floor(Math.random() * 127); 
		color_rgb[1] = Math.floor(Math.random() * 127); 
		color_rgb[2] = Math.floor(Math.random() * 127);
		 
		// パステルカラーにする
		color_rgb[Math.floor(Math.random() * 3)] = 255;
		
		// RGBカラーの結合
		g_color = color_rgb[0] + "," + color_rgb[1] + "," + color_rgb[2];
	}
	return g_color;
}

/**
 * 自分の名称を取得する。
 * @return 名称
 */
function getGlobalUserName()
{
	var val = localStorage.getItem("myname");
	
	if (val == null)
	{
		return DEFAULT_NAME;
	}
	
	return val;
}

/**
 * 自分の名称を設定する。
 * @param {string} user_name
 */
function setGlobalUserName(user_name)
{
	// ユーザー名を更新
	localStorage.setItem("myname", user_name);
}

////////////////////////////////////////////////////////////////////////////////
//
// クラス
//
////////////////////////////////////////////////////////////////////////////////
/**
 * アイデアクラス
 */
var Idea = function(id, comment, image, color, size, parent_id)
{
	// ID
	this.id = id;
	// 親ID
	this.parent_id = (parent_id)? parent_id : "";
	// コメント
	this.comment = comment;
	// イメージ
	this.image = image;
	// 子のIDリスト
	this.children = new Array();
	// 背景色
	this.color = color;
	// サイズ
	this.size = size;
	// 位置(y)
	this.top = 
		Math.floor(Math.random() * g_view_layer.height()) - g_canvas_layer.offset().top;
	// 位置(x)
	this.left = 
		Math.floor(Math.random() * g_view_layer.width()) - g_canvas_layer.offset().left;
	
	
	/**
	 * 子を追加する。
	 * @param id 子のID 
	 */
	this.addChild = function(id)
	{
		this.children.push(id);
	}
	
	/**
	 * 子を削除する。
	 * @param 子のID
	 */
	this.removeChild = function(id)
	{
		this.children.pop(id);
	}
	
	/**
	 * 親IDを取得する。
	 * @return 親ID 
	 */
	this.getParentId = function()
	{
		return this.parent_id;
	}
	
	/**
	 * 親子関係を持たないアイデアであるかどうかを取得する。
	 */
	this.isAlone = function()
	{
		if (this.parent_id == "" && this.children.length == 0)
		{
			return true;
		}
		return false;
	}
	
	/**
	 * 直径を計算する。
	 * @return 直径 
	 */
	this.calcSize = function()
	{
		return Math.floor( (this.children.length * 10 + 100) * getGlobalScale());
	}
	
	/**
	 * 文字サイズを計算する。
	 * @return 文字サイズ 
	 */
	this.calcFontSize = function()
	{
		return Math.floor(16 * getGlobalScale());
	}
	
	/**
	 * 選択された場合の動作を規定する。
	 */
	this.select = function()
	{
		// 選択状態を規定したCSSを適用
		// $("#" + this.id).css("-webkit-animation-name", "fuyopika_motion");
		$("#" + this.id).addClass("selected");
	}
	
	/**
	 * 選択解除された場合の動作を規定する。
	 */
	this.deselect = function()
	{
		// 選択解除状態を規定したCSSを適用
		// $("#" + this.id).css("-webkit-animation-name", "fuyo_motion");
		$("#" + this.id).removeClass("selected");
	}
	
	/**
	 * 再描画を行う。
	 */
	this.invalidate = function()
	{
		// アイデアを取得
		var idea = $("#" + this.id);
    	// 親アイデアオブジェクトを取得
			var parentIdeaObj = (this.parent_id)? g_idea_map[String(this.parent_id)] : null;
		// サイズを取得
		var parentSize = this.calcSize();
		// 文字サイズを取得
		var tmp_font_size = this.calcFontSize();
		// 親アイデアが描画されている角度を算出
		var deg_parent = (this.parent_id)? (360	/ parentIdeaObj.children.length * parentIdeaObj.children.indexOf(this.id) + 180) % 360 : -1;
		// 子アイデアの描画角度を算出(親アイデアがいる場合は、それを考慮する)
		var deg = (this.parent_id)? 360 / (this.children.length + 1) : 360 / this.children.length;
		
		// 子アイデアの表示位置を更新
			var index = 0;
			var draw_index = 0;
			while (index < this.children.length)
			{
				 // 親アイデアがある場合は描画順序0番目を親とする
				 if (draw_index == 0 && this.parent_id)
				 {
						draw_index++;
						continue;
				 }
				 
				 // 描画対象アイデアのサイズを取得
				var childSize = g_idea_map[String(this.children[index])].calcSize();
				 
				// 子の位置を計算
				var distant = Math.floor((parentSize + childSize) / 2);
				var diff = Math.floor((parentSize - childSize) / 2);
				var x = Math.floor(this.left + diff + distant * Math.cos( ( ((this.parent_id)? deg_parent : 0) + deg * draw_index) * Math.PI / 180));
				var y = Math.floor(this.top + diff + distant * Math.sin( ( ((this.parent_id)? deg_parent : 0) + deg * draw_index) * Math.PI / 180));
				 
				g_idea_map[String(this.children[index])].top = y;
				g_idea_map[String(this.children[index])].left = x;
				 
				index++;
				draw_index++;
			}
		
		// 自分の表示位置を更新
		idea.parent().css({
			"top" : this.top + "px",
			"left" : this.left + "px"
		});
		idea.css({
			"font-size" : tmp_font_size + "px",
			"width" : parentSize + "px",
			"height" : parentSize + "px",
			"border-radius" : Math.floor(parentSize)/2 + "px",
			"-moz-border-radius" : Math.floor(parentSize)/2 + "px",
			"-webkit-border-radius" : Math.floor(parentSize)/2 + "px",
			"background-image" : "-webkit-gradient(radial, center center, 0, center center, " + parentSize * 0.75 + ", from(rgba(" + this.color + ", 1)), to(rgba(255, 255, 255, 1)))",
		});
		
		// 子要素の再描画を行う
		for (var i = 0; i < this.children.length; i++)
		{
			g_idea_map[String(this.children[i])].invalidate();
		}
	}
	
	/**
	 * タグオブジェクトとして取得する。
	 */
	this.toTag = function()
	{
		// サイズ情報を取得
		var tmp_size = this.calcSize();
		var tmp_font_size = this.calcFontSize();
		
		// アイデアのコンテナを生成
		var container = $("<div>")
			.addClass("idea_container")
			.css({
				"top" : this.top + "px",
				"left" : this.left + "px"
			});
		
		// アイデアそのものを生成
		var idea = $("<div>");
		
		if (this.comment) {
			idea.text(this.comment);
		}
		else if (this.image) {
			idea.append(this.image);
		}
		
		idea
			.attr("id", this.id)
			.addClass("idea")
			.css({
				"font-size" : tmp_font_size + "px",
				"width" : tmp_size + "px",
				"height" : tmp_size + "px",
				"border-radius" : Math.floor(tmp_size)/2 + "px",
				"-moz-border-radius" : Math.floor(tmp_size)/2 + "px",
				"-webkit-border-radius" : Math.floor(tmp_size)/2 + "px",
				"background" : "-moz-radial-gradient( cover, rgba(" + this.color + ",1), rgba(255, 255, 255, 1))",
				"background-image" : "-webkit-gradient(radial, center center, 0, center center, " + tmp_size * 0.75 + ", from(rgba(" + this.color + ", 1)), to(rgba(255, 255, 255, 1)))",
				"border" : "1px solid rgba(" + this.color + ", 0.7)"
			})
			.bind("webkitAnimationEnd", function(e)
			{
				$(this).css("-webkit-animation-name", "");
			})
			.bind("mouseover", function()
			{
				$(this).css("-webkit-animation-name", "fuyo_motion");
			})
			.appendTo(container);
		
		return container;
	}
}

////////////////////////////////////////////////////////////////////////////////
//
// アイデア描画関数
//
////////////////////////////////////////////////////////////////////////////////
/**
 * 初期描画を行う。
 */
function initDraw()
{
	for (var i in g_idea_map)
	{
		newDraw(g_idea_map[i]);
	}
}

/**
 * 新規アイデアの描画を行う。
 * @param 描画対象のアイデアオブジェクト
 */
function newDraw(targetIdea)
{
	targetIdea.toTag().appendTo(g_canvas_layer)
	.draggable({
		containment: "#canvas_layer",
		opacity: 0.5,
		cursor: 'move',
		zIndex: 10001,
		start: function(e, ui)
		{
			// 自分のデータを検索
			var tmpIdea = g_idea_map[String($(this).children().attr("id"))];
			var curr_top = tmpIdea.top;
			var curr_left = tmpIdea.left;
			
			// 祖先を検索
			while (tmpIdea.getParentId() != "")
			{
				tmpIdea = g_idea_map[String(tmpIdea.getParentId())];
			}
			
			// 親と当該オブジェクトの座標差分を抽出
			var diff_y = tmpIdea.top - curr_top;
			var diff_x = tmpIdea.left - curr_left;
			
			$(this).data("ancient_id", tmpIdea.id);
			$(this).data("diff_y", diff_y);
			$(this).data("diff_x", diff_x);
		},
		stop: function(e, ui)
		{
			// 祖先のデータを取得
			var ancientObj = g_idea_map[String($(this).data("ancient_id"))];
			
			// 祖先に当該オブジェクトの x, y  + 差分( x, y )を設定
			ancientObj.top = ui.position.top + $(this).data("diff_y");
			ancientObj.left = ui.position.left + $(this).data("diff_x");
			
			// 親を引数としてrefreshDraw()
			refreshDraw(ancientObj);
			
//			var ideaObj = g_idea_map[String($(this).children(".idea").attr("id"))];
//			ideaObj.top = ui.position.top;
//			ideaObj.left = ui.position.left;
//			refreshDraw(ideaObj);
		}
	})
	.droppable({
		containment: "#canvas_layer",
		zIndex: 10000,
		drop: function(e, ui)
		{
			// 受容体オブジェクト情報
			var receptorObj = g_idea_map[String($(this).children(".idea").attr("id"))];
			// D&Dされたオブジェクトの情報
			var senderObj = g_idea_map[String(ui.draggable.children().attr("id"))];
			
			// 孤立アイデアに限り、受容体の傘下に収める
			if (senderObj && senderObj.isAlone())
			{
				// 親子関係を設定
				receptorObj.addChild(senderObj.id);
				senderObj.parent_id = receptorObj.id;

				// 親子関係を送信
				sendLinkage(senderObj.id, receptorObj.id);
			}
		}
	});
}

/**
 * アイデア一族の再描画を行う。
 * @param 描画対象のアイデアオブジェクト 
 */
function refreshDraw(targetIdea)
{
	// 祖先を検索する
	var tmpIdea = targetIdea;
	while (tmpIdea.getParentId() != "")
	{
		tmpIdea = g_idea_map[String(tmpIdea.getParentId())];
	}
	
	tmpIdea.invalidate();
} 

/**
 * メッセージオブジェクトを処理する
 * @param {object} obj メッセージオブジェクト
 */
function message(obj)
{
	// 通知メッセージの場合
	if ("announcement" in obj)
	{
/*
		var topic_id = obj.announcement[0];
		var session_id = esc(String(obj.announcement[1]));
		var flg = obj.announcement[2];
		
		if (isThisTopic(topic_id)) 
		{
		}
		if (isThisTopic(topic_id)) 
		{
			var user_name = esc(localStorage.getItem(session_id));
		
			// チャット表示領域の更新
			$("<p>").append($("<em>").text(user_name)).appendTo($("div#chat"));
		
			// 画面上で通知
			$("<p>").append($("<em>").text(user_name)).appendTo($("div#notice"));
			$("div#notice").addClass("show");
		}
*/
	}
	// トピック情報の場合
	else if ("topic" in obj)
	{
		// トピック名表示領域の更新
		$("h1").text(obj.topic[1]);
		if (obj.topic[2]) {
			$("div#topic_desc").text(obj.topic[2]);
		}
		else {
			$("div#topic_desc").text("説明はありません。");
		}
	}
	// トピックリスト情報の場合
	else if ("topic_list" in obj)
	{
		$("div#load_topic_title").empty();
		if (obj.topic_list.length == 0) {
			$("#topic_message").text("参加できるトピックがありません。");
		}
		else {
			var ul = $("<ul>");
			for (var i = 0; i < obj.topic_list.length; i++) {
				$("<li>")
				.data("topic_id", obj.topic_list[i].topic[0])
				.click(function(){
					location.href = "/index?topic_id=" + $(this).data("topic_id");
				})
				.append($("<span>")
				.text(esc(obj.topic_list[i].topic[1])))
				.appendTo(ul);
			}
			ul.appendTo($("div#load_topic_title"));
		}
	}
	// 関連付け情報の場合
	else if ("linkage" in obj)
	{
		if (isThisTopic(obj.linkage[0])) {
			// 親子関係を設定
			var ideaObj = g_idea_map[String(obj.linkage[1])];
			g_idea_map[String(obj.linkage[2])].addChild(obj.linkage[1]);
			ideaObj.parent_id = obj.linkage[2];
	
			// オブジェクトの位置を調整
			refreshDraw(ideaObj);
		}
	}
	// テキスト情報の場合
	else if ("message" in obj)
	{
		if (isThisTopic(obj.message[MESSAGE_TOPIC_ID])) {
			// チャット表示領域の更新
			$("<p>")
				.append($("<b>")
				.text(esc(localStorage.getItem(String(obj.message[MESSAGE_USER_ID]))) + ":"))
				.append(esc(obj.message[MESSAGE_TEXT])).appendTo($("div#chat"));
			
			// メッセージの情報を取得
			var id = obj.message[MESSAGE_IDEA_ID];
			var txt = obj.message[MESSAGE_TEXT];
			var color = obj.message[MESSAGE_COLOR];
			var parentId = obj.message[MESSAGE_PARENT_ID];
			var size = 100; // サーバーからわたってこないので固定値
			
			// アイデア生成
			var newIdea = new Idea(id, txt, null, color, size, parentId);

			// マップへ追加
			g_idea_map[String(id)] = newIdea;
			
		if (parentId && g_idea_map[String(parentId)]) // TODO 「&&」の後は暫定コードである、サーバーから全データが送信されるべき
			{
				// 親へ子の追加を通知
				g_idea_map[String(parentId)].addChild(id);
			}
			
			// 新アイデアを描画
			newDraw(newIdea);
			
			if (parentId)
			{
				// 系列アイデアを再描画
				refreshDraw(newIdea);
			}
			
			// TODO:要仕様検討
			//transparent(obj.message[1]);
		}
	}
	// イメージ情報の場合
	else if ("image" in obj)
	{
		if (isThisTopic(obj.image[MESSAGE_TOPIC_ID])) {
			// チャット表示領域の更新
			$("<p>")
				.append($("<b>")
				.text(esc(localStorage.getItem(String(obj.image[MESSAGE_USER_ID]))) + ":"))
				.append("[イメージが追加されました]").appendTo($("div#chat"));
			
			// メッセージの情報を取得
			var id = obj.image[MESSAGE_IDEA_ID];
			var img = $("<img>")
				.addClass("idea_image")
				.attr("src", obj.image[MESSAGE_TEXT]);
			var color = obj.image[MESSAGE_COLOR];
			var parentId = obj.image[MESSAGE_PARENT_ID];
			var size = 100; // サーバーからわたってこないので固定値
	
			// アイデア生成
			var newIdea = new Idea(id, null, img, color, size, parentId);

			// マップへ追加
			g_idea_map[String(id)] = newIdea;
			
			if (parentId && g_idea_map[String(parentId)]) // TODO 「&&」の後は暫定コードである、サーバーから全データが送信されるべき
			{
				// 親へ子の追加を通知
				g_idea_map[String(parentId)].addChild(id);
			}
			
			// 新アイデアを描画
			newDraw(newIdea);
			
			if (parentId)
			{
				// 系列アイデアを再描画
				refreshDraw(newIdea);
			}
			
			// TODO:要仕様検討
			//transparent(obj.message[1]);
		}
	}
	// 接続ユーザー情報の受信
	else if ("user_list" in obj)
	{
		// TODO Topicに特化させる? or データは受信するけどTopicにマッチする時だけchat履歴に表示?
		var user_list = obj.user_list;
		for (var i=0; i<user_list.length; i++)
		{
			// 各要素から名前とセッションIDを抽出
			var each_name = user_list[i].name;
			var each_session_id = user_list[i].session_id;
			
			// ローカルDBへ保存
			localStorage.setItem(String(each_session_id), each_name);
		}
	}
	// 新規ユーザーの接続通知
	else if ("new_user" in obj)
	{
		var new_user_name = obj.new_user.name;
		var new_session_id = obj.new_user.session_id;
		var new_user_topic_id = obj.new_user.topic_id;
		
		// Topicに特化させる
		if (isThisTopic(new_user_topic_id)) {
			var user_name = esc(new_user_name);
			// 既存ユーザーの場合
			if (localStorage.getItem(new_session_id)) {
				// 接続中ユーザ表示領域の更新
				$("p#atnd" + new_session_id).children().text(user_name);
			}
			// 新規ユーザーの場合
			else {
				// チャット表示領域の更新
				var ann = user_name + "が接続しました。";
				$("<p>").append($("<em>").text(ann)).appendTo($("div#chat"));
				// 接続中ユーザの追加
				g_connected_user_list.push(new_session_id);
				// 接続中ユーザ表示領域の更新
				$("<p>").append($("<em>").text(new_user_name))
					.attr("id", "atnd" + new_session_id)
					.attr("title", "session_id:" + new_session_id)
					.appendTo($("div#attendee"));
			}
			// ローカルDBへ保存
			localStorage.setItem(String(new_session_id), new_user_name);
		}
	}
	// 既存ユーザーの切断通知
	else if ("delete_user" in obj)
	{
		var delete_session_id = obj.delete_user.session_id;
		var delete_user_topic_id = obj.delete_user.topic_id;
		
		// Topicに特化させる
		if (isThisTopic(delete_user_topic_id)) {
			// ローカルDBからユーザ名を取得
			var user_name = esc(localStorage.getItem(delete_session_id));
			// チャット表示領域の更新
			var ann = user_name + "が切断しました。";
			$("<p>").append($("<em>").text(ann)).appendTo($("div#chat"));
			// 接続中ユーザの削除
			for (var i = 0; i < g_connected_user_list.length; i++) {
				if (g_connected_user_list[i] == delete_session_id) {
					g_connected_user_list.splice(i, 1);
				}
			}
			// 接続中ユーザ表示から削除
			$("p#atnd" + delete_session_id).remove();
		}
	}
	// 接続ユーザーリストの受信
	else if ("connected_user_list" in obj)
	{
		// サーバ側の処理でトピックが一致したアイテムのみ入っている
		g_connected_user_list = obj.connected_user_list;
	}
	
	$("div#chat").attr("scrollTop", "1000000");
}

////////////////////////////////////////////////////////////////////////////////
//
// サーバ連携関数
//
////////////////////////////////////////////////////////////////////////////////
/**
 * WebSocketでアイデアのテキスト情報を送信する。
 */
function sendText()
{
	var text = $("input#text").val();
	var topic_id = $("#topic_id").attr("value");
	var parent_id = g_selected_id.length > 0 ? g_selected_id[0] : undefined;
	
	$("input#text").val("");
	socket.send({ message: [topic_id, text, getGlobalColor(), parent_id] });
}

/**
 * WebSocketでアイデアのイメージ情報を送信する。
 * @param {object} dataURL_file DataURLファイル
 */
function sendImage(dataURL_file) 
{
	var topic_id = $("#topic_id").attr("value");
	var parent_id = g_selected_id.length > 0 ? g_selected_id[0] : undefined;
	
	socket.send({image: [topic_id, dataURL_file, getGlobalColor(), parent_id]});
}
	
/**
 * WebSocketでアイデアの関連付け情報を送信する。
 * @param {string} obj_id オブジェクトID
 * @param {string} parent_id 親のオブジェクトID
 */
function sendLinkage(obj_id, parent_id)
{
	var topic_id = $("#topic_id").attr("value");
	socket.send({ linkage: [topic_id, obj_id, parent_id] });
}

/**
 * WebSocketでトピック情報をロード要求する。
 */
function loadTopic() 
{
	socket.send({ load: [$("#topic_id").attr("value")] });
}

/**
 * WebSocketでトピック一覧情報をロード要求する。
 */
function loadTopicList() 
{
	socket.send({ topiclist: "topiclist" });
}

/**
 * WebSocketでユーザー情報一覧のロード要求を行う。
 */
function loadUserList()
{
	socket.send({ userlist: "userlist" })
}

/**
 * WebSocketでユーザー登録を要求する。
 * @param {string} user_name ユーザー名
 */
function registerUser(user_name)
{
	socket.send({ registeruser: { user_name: user_name, topic_id: $("#topic_id").attr("value") } });
}

////////////////////////////////////////////////////////////////////////////////
//
// 汎用関数
//
////////////////////////////////////////////////////////////////////////////////
/**
 * エスケープを行う。
 * @param string msg 対象文字列
 * @return 
 */
function esc(msg)
{
	if (msg == null)
	{
		return msg;
	}
	return msg.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

/**
 * 指定したトピックIDが現在選択中のトピックのものかを判定する。
 * @param {string} topic_id トピックID
 * @return 
 */
function isThisTopic(topic_id)
{
	if (topic_id == $("#topic_id").attr("value")) {
		return true;
	}
	return false;
}

/**
 * 現在のキャンバスのビュー位置を表示する
 * @param {number} canvas_top 現在のキャンバスの左上y座標
 * @param {number} canvas_left  現在のキャンバスの左上x座標
 * @return 
 * @type 
 */
function dispCurrentPosition(canvas_top, canvas_left) 
{
	var max_top = g_view_layer.offset().top - (g_view_layer.height() - g_canvas_layer.height());
	var max_left = g_view_layer.offset().left - (g_view_layer.width() - g_canvas_layer.width());

	// 現在の座標を表示する
	$("#cursor_position").text(
		"top:" + (g_view_layer.offset().top - canvas_top) + "(0 - " + max_top + ") / " +  
		"left:" + (g_view_layer.offset().left - canvas_left) + "(0 - " + max_left + ")");
}

/**
 * キャンバスレイヤーのサイズを超えるx, y値を丸める
 * @param {number} canvas_top 現在のキャンバスの左上y座標
 * @param {number} canvas_left  現在のキャンバスの左上x座標
 * @return 
 * @type 
 */
function roundPosition(canvas_top, canvas_left) 
{
	var rounded_canvas_top = canvas_top;
	var rounded_canvas_left = canvas_left;
	
	// ビューレイヤーがキャンバスレイヤーの範囲を超えないようにする
	if (canvas_top > 0) {
		rounded_canvas_top = 0;
	}
	if (canvas_top + g_canvas_layer.height() < g_view_layer.height()) {
		rounded_canvas_top = g_view_layer.height() - g_canvas_layer.height();
	}
	if (canvas_left > 0) {
		rounded_canvas_left = 0;
	}
	if (canvas_left + g_canvas_layer.width() < g_view_layer.width()) {
		rounded_canvas_left = g_view_layer.width() - g_canvas_layer.width();
	}
	return {top: rounded_canvas_top, left: rounded_canvas_left};
}

////////////////////////////////////////////////////////////////////////////////
//
// イベントハンドラー
//
////////////////////////////////////////////////////////////////////////////////
/**
 * Ctrlキーを押下する際、画面スクロールモードを開始する
 */
$(window).keydown(function(e) {
	if (e.keyCode == 17) {
		g_scroll_layer
			.css({
				"left": g_view_layer.css("left"),
				"top": g_view_layer.css("top"),
				"width": g_view_layer.width(),
				"height": g_view_layer.height(),
				"z-index": 9999,
				"display": ""
			});

		var offset = g_canvas_layer.offset();
		dispCurrentPosition(offset.top, offset.left);
		
		g_scroll_layer.draggable({
			helper: function() {
				return $("<div />");
			},
			start: function(e, ui) {
				// キャンバスレイヤーの画面上の初期位置を取得
				var offset = g_canvas_layer.offset();
				g_canvas_layer
					.data("top0", offset.top)
					.data("left0", offset.left);
			},
			drag: function(e, ui) {
				// キャンバスレイヤーの位置を調整する
				var dragTop = ui.position.top + g_canvas_layer.data("top0");
				var dragLeft = ui.position.left + g_canvas_layer.data("left0");
				
				g_canvas_layer
					.css("top", dragTop).css("bottom", -dragTop)
					.css("left", dragLeft).css("right", -dragLeft)

				var roundedPosition = roundPosition(dragTop, dragLeft);
				dispCurrentPosition(roundedPosition.top, roundedPosition.left);
			},
			stop: function(e, ui) {
				// キャンバスレイヤーの位置を調整する
				var dragTop = ui.position.top + g_canvas_layer.data("top0");
				var dragLeft = ui.position.left + g_canvas_layer.data("left0");
				var roundedPosition = roundPosition(dragTop, dragLeft);
				
				g_canvas_layer
					.css("top", roundedPosition.top).css("bottom", -roundedPosition.top)
					.css("left", roundedPosition.left).css("right", -roundedPosition.left)

				dispCurrentPosition(roundedPosition.top, roundedPosition.left);
			}
		});
	}
});

/**
 * Ctrlキーを離した際、画面スクロールモードが終了する
 */
$(window).keyup(function(e) {
	if (e.keyCode == 17) {
		g_scroll_layer
			.css({
				"z-index": -1,
				"display": "none"
				});
	}
	$("#cursor_position").text("");
});

/**
 * 入力フィールドを位置可動にする
 */
$("#input_form").draggable({
	opacity: 0.5,
	cursor: "move"
});
/**
 * 入力フィールドの位置を指定する
 * href指定のときに崩れるため、こちらに記述
 */
$("#input_form").css({
	position: "absolute",
	left: "0px",
	bottom: "0px"
});

/**
 * メニューの履歴表示切り替えボタンクリックイベントハンドラー
 */
$("#menu_history").click(function ()
{
	var chat_history = $("#chat_window");
	if (chat_history.hasClass("show"))
	{
		chat_history.removeClass("show");
	}
	else
	{
		chat_history.addClass("show");
	}
});

/**
 * 接続中ユーザ表示ボタンクリックイベントハンドラー
 */
$("#menu_attendee").click(function()
{
	var attendee = $("#attendee_window");

	if (attendee.hasClass("show"))
	{
		attendee.removeClass("show");
	}
	else
	{
		attendee.addClass("show");
	}
});

/**
 * 新規トピック作成ボタンクリックイベントハンドラー
 */
$("#menu_rename").click(function()
{
	$("#rename_layer").lightbox_me({
		centered: true,
		zIndex: 50000,
		closeEnter: true,
		onLoad: function()
		{ 
			$("#rename_name_text").focus();
			$("#rename_name_text").val(getGlobalUserName());
		},
		onClose: function()
		{
			// ユーザー名を保存
			setGlobalUserName($("#rename_name_text").val());
			
			// 自分のユーザー情報を送信
			registerUser(getGlobalUserName());
			
			return false;
		}
	});
	
	return false;
});

/**
 * 新規トピック作成ボタンクリックイベントハンドラー
 */
$("#menu_newtopic").click(function()
{
	$("#new_topic_layer").lightbox_me({
		centered: true,
		zIndex: 50000,
		onLoad: function()
		{ 
			$("#new_topic_layer").find("input:first").focus()
		}
	});
	
	return false;
});

/**
 * 既存トピック読込ボタンクリックイベントハンドラー
 */
$("#menu_loadtopic").click(function()
{
	$("#load_topic_layer").lightbox_me({
		centered: true,
		zIndex: 50000,
		onLoad: function()
		{ 
			$("#load_topic_layer").find('input:first').focus()
		}
	});
	loadTopicList();
	
	return false;
});

/**
 * ヘルプボタンクリックイベントハンドラー
 */
$("#menu_help").click(function()
{
	$("#help_layer").lightbox_me({
		centered: true,
		zIndex: 50000,
		onLoad: function()
		{ 
		}
	});
	
	return false;
});

/**
 * 送信ボタンのクリックイベントハンドラー
 */
$("div#send_msg").click(function ()
{
	// 空文字は送信しない
	if ($("input#text").val()) {
		sendText();
	}
	// テキストボックスにフォーカスする
	$("input#text").focus();
});

/**
 * テキストボックスのキーダウンハンドラー
 */
$("input#text").keydown(function(e)
{
	if (e.keyCode == 13)
	{
		$("div#send_msg").click();
	}
});

/**
 * アイデアのクリックハンドラー
 */
$("div.idea").live("click", function()
{
	// クリックされたアイデアのIDを取得
	var thisId = $(this).attr("id");
	
	// 現在選択されているアイデアのIDを取得
	var prevId = g_selected_id.pop();
	
	if (prevId)
	{
		// 選択解除
		g_idea_map[String(prevId)].deselect();
	}
	
	// 異なるアイデアをクリックした場合のみ
	if (prevId != thisId)
	{
		// 選択
		g_idea_map[String(thisId)].select();
		g_selected_id.push(thisId);
	}
	$("input#text").focus();
});

/**
 * アイデアのホバーイベントハンドラー
 */
$("div.idea:parent").live("hover", function(e)
{
	// マウスオーバー時に最前面にする
	switch (e.type) {
		case "mouseenter":
			$(this).parent().css("z-index", 10000);
			$(this).addClass("mouseover");
			break;
		case "mouseleave":
			$(this).parent().css("z-index", 0);
			$(this).removeClass("mouseover");
			break;
		default:
			break;
	}
});

/**
 * 新トピック作成ボタンのクリックハンドラー
 */
$("#new_topic_ok").click(function(){
	location.href="/new?subject=" + $("#new_topic_title").val() +"&description=" + $("#new_topic_desc").val();
	return false;
});

////////////////////////////////////////////////////////////////////////////////
//
// ファイルドラッグ
//
////////////////////////////////////////////////////////////////////////////////
$("#canvas_layer")
	.bind("dragenter", function()
	{
		$(this).addClass("drag_over"); 
		return false;
	})
	.bind("dragleave", function()
	{
		$(this).removeClass("drag_over"); 
		return false;
	})
	.bind("dragover", function(e)
	{
		e.preventDefault(); 
		return false;
	})
	.bind("drop", function(e)
	{
		e.preventDefault();

		if (e.originalEvent.dataTransfer) {
			// ドロップされたファイルのリストを取得
			var files = e.originalEvent.dataTransfer.files;
			
			if (files.length > 0) {
				var file = files[0];
				if (!/^image/.test(file.type)) {
					alert('イメージファイルをドロップしてください。');
					return false;
				}
				
				// ファイル読み取りオブジェクト生成
				var reader = new FileReader();
				reader.readAsDataURL(file);
				
				// ファイル読み込み正常終了イベントリスナ
				reader.onload = function(e){
					sendImage(reader.result);
				};
			}
		}
		return false;
	});

////////////////////////////////////////////////////////////////////////////////
//
// メイン処理
//
////////////////////////////////////////////////////////////////////////////////
// テキストボックスにフォーカスする
$("input#text").focus();

// 名称がデフォルトのままなら、変更を促す
if (getGlobalUserName() == DEFAULT_NAME)
{
	$("#register_name_layer").lightbox_me({
		centered: true,
		zIndex: 50000,
		closeEnter: true,
		onLoad: function()
		{ 
			$("#register_name_text").focus();
			$("#register_name_text").val(getGlobalUserName());
		},
		onClose: function()
		{
			// ユーザー名を保存
			setGlobalUserName($("#register_name_text").val());
			
			// 自分のユーザー情報を送信
			registerUser(getGlobalUserName());
			
			return false;
		}
	});
}

// サーバに接続する
var socket = new io.Socket(null, {port: 80, rememberTransport: false});
socket.connect();

// 自分のユーザー情報を送信
registerUser(getGlobalUserName());

// ユーザー情報一覧のロード要求を行う
loadUserList();

// トピック情報一覧のロード要求を行う
loadTopic();

// サーバーからのメッセージ処理ハンドラを定義
socket.on("message", function(obj)
{
	if ("buffer" in obj)
	{
		$("div#chat").text("");
		
		// テキスト情報を反映
		for (var i in obj.buffer)
		{
			var msg;
			if ("message" in obj.buffer[i]) {
				// 親アイデア情報は分ける
				var obj_msg = obj.buffer[i].message;
				msg = {
					message:[
						obj_msg[MESSAGE_USER_ID], 
						obj_msg[MESSAGE_TOPIC_ID],
						obj_msg[MESSAGE_IDEA_ID], 
						obj_msg[MESSAGE_TEXT], 
						obj_msg[MESSAGE_COLOR], 
						""] };
			}
			else if ("image" in obj.buffer[i]) {
				// 親アイデア情報は分ける
				var obj_msg = obj.buffer[i].image;
				msg = {	
					image:[
						obj_msg[MESSAGE_USER_ID], 
						obj_msg[MESSAGE_TOPIC_ID],
						obj_msg[MESSAGE_IDEA_ID], 
						obj_msg[MESSAGE_TEXT], 
						obj_msg[MESSAGE_COLOR], 
						""] };
			}
			message(msg);
		}

		// 関連付け情報を反映
		for (var i in obj.buffer)
		{
			if ("message" in obj.buffer[i]) {
				// 親アイデアIDを持っている場合
				if (obj.buffer[i].message[MESSAGE_PARENT_ID]) {
					var obj_msg = obj.buffer[i].message;
					var linkage = { 
						linkage: [
							obj_msg[MESSAGE_TOPIC_ID],
							obj_msg[MESSAGE_IDEA_ID], 
							obj_msg[MESSAGE_PARENT_ID]] };
					message(linkage);
				}
			}
			else if ("image" in obj.buffer[i]) {
				// 親アイデアIDを持っている場合
				if (obj.buffer[i].image[MESSAGE_PARENT_ID]) {
					var obj_msg = obj.buffer[i].image;
					var linkage = { 
						linkage: [
							obj_msg[MESSAGE_TOPIC_ID],
							obj_msg[MESSAGE_IDEA_ID], 
							obj_msg[MESSAGE_PARENT_ID]] };
					message(linkage);
				}
			}
		}
	}
	else
	{
		message(obj);
	}
});

}) // end of $(function())

